package compoundDB.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import compoundDB.core.GUIController;
import compoundDB.database.container.ColumnField;
import compoundDB.database.container.SearchOption;
import compoundDB.database.enumeration.SearchOptionType;

/**
 * Dialog for the advance properies search. The dialog handles all the searching
 * so all that is left is for others to do is to get results
 * 
 * @author Michael
 */
@SuppressWarnings("serial")
public class DialogAdv extends JDialog
{

	private static final int dialogWidth = 500;
	private static final int dialogHieght = 200;
	private String[] cols;
	private ArrayList<AdvOption> opps;
	private JPanel contentPane;
	private DialogAdv thisDialog;
	private JButton butAdd;
	private JButton butConfirm;
	private GUIController guic;
	private ResultsScreen screen;

	/**
	 * Creates and shows the dialog.
	 * 
	 * @param columnNames
	 *            the properies to be searched over
	 * @param screen
	 *            the results screen that needs to know about the results
	 * @param guic
	 *            the guicontroller that will handle the searching
	 */
	public DialogAdv(String[] columnNames, ResultsScreen screen, GUIController guic)
	{
		this.screen = screen;
		this.cols = columnNames.clone();
		this.guic = guic;
		thisDialog = this;
		opps = new ArrayList<AdvOption>();
		opps.add(new AdvOption());
		setUpDialog();
		refreshOpps();
		checkSearch();
		this.setVisible(true);
	}

	/**
	 * Creates the initial buttons "+" , "Search", and "Cancel"
	 * 
	 * @return the component that has thes buttons
	 */
	private Component addButtons()
	{
		butAdd = new JButton("+");
		butAdd.setToolTipText("Add a parameter to the search");
		butAdd.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent e)
			{
				opps.add(new AdvOption());
				refreshOpps();
				checkSearch();
			}
		});
		butConfirm = new JButton("Search");
		butConfirm.setToolTipText("Make the Search");
		butConfirm.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent e)
			{
				makeSearch();
				thisDialog.dispose();
			}
		});
		JButton butCancel = new JButton("Cancel");
		butCancel.setToolTipText("Cancel the advanced search");
		butCancel.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent e)
			{
				thisDialog.dispose();
			}
		});

		JPanel big = new JPanel();
		big.setLayout(new BoxLayout(big, BoxLayout.X_AXIS));
		big.add(Box.createHorizontalGlue());
		big.add(butAdd);
		big.add(Box.createHorizontalGlue());
		big.add(butConfirm);
		big.add(Box.createHorizontalGlue());
		big.add(butCancel);
		big.add(Box.createHorizontalGlue());
		return big;
	}

	/**
	 * Refreshes the panel containing all the Component (both constant and the
	 * search ones)
	 */
	private void refreshOpps()
	{
		if (contentPane != null)
		{
			this.remove(contentPane);
		}
		contentPane = new JPanel();
		contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS));
		for (int i = 0; i < opps.size(); i++)
		{
			contentPane.add(opps.get(i));
			contentPane.add(Box.createRigidArea(new Dimension(10, 0)));
		}
		contentPane.add(Box.createVerticalGlue());
		contentPane.add(addButtons());
		contentPane.add(Box.createVerticalStrut(10));
		add(contentPane);
		contentPane.updateUI();
	}

	/**
	 * checks if a search can be made from the given info if it cant it takes
	 * away the "Search" button
	 */
	private void checkSearch()
	{
		if (opps.size() == 0)
		{
			butConfirm.setEnabled(false);
			return;
		}
		for (int i = 0; i < opps.size(); i++)
		{
			if (opps.get(i).getSearchOption() == null)
			{
				butConfirm.setEnabled(false);
				return;
			}
		}
		butConfirm.setEnabled(true);
	}

	/**
	 * Makes the search Can only be called if check search hasnt stolen the
	 * button so no need to do checking
	 */
	private void makeSearch()
	{
		List<SearchOption> opplist = new ArrayList<SearchOption>();
		for (int i = 0; i < opps.size(); i++)
		{
			opplist.add(opps.get(i).getSearchOption());
		}
		guic.advancedSearch(opplist);
		screen.newSearchResults = true;

	}

	/**
	 * Sets up the basic dialog properties
	 */
	private void setUpDialog()
	{
		this.setModal(true);
		setSize(dialogWidth, dialogHieght);
		setTitle("Editing Columns");
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);

		Dimension size = getToolkit().getScreenSize();
		setLocation(size.width / 3 * 2 - getWidth() / 2, size.height / 3 - getHeight() / 2);

		this.setAlwaysOnTop(true);
	}

	/**
	 * removes one of the search options (called for the search option its self)
	 * 
	 * @param opp
	 *            the option to be removed
	 */
	private void removeOpp(AdvOption opp)
	{
		opps.remove(opp);
		refreshOpps();
		if (opps.size() == 0)
		{
			butConfirm.setEnabled(false);
			return;
		}
	}

	/**
	 * a search option
	 */
	class AdvOption extends JPanel
	{

		private JButton butRemove;
		private JComboBox propType;
		private JComboBox optType;
		private JTextField searchQueary;
		private AdvOption thisOpp;

		/**
		 * Creates a Search Option Uses cols and the guic straight from the
		 * DialogAdv class
		 */
		public AdvOption()
		{
			thisOpp = this;
			butRemove = new JButton("-");
			butRemove.addActionListener(new ActionListener()
			{

				@Override
				public void actionPerformed(ActionEvent arg0)
				{
					removeOpp(thisOpp);
					checkSearch();
				}
			});
			AdvListener listener = new AdvListener();
			propType = new JComboBox(cols);
			propType.addItemListener(listener);
			optType = new JComboBox(guic.getAllowedSearchOptionsInStrings(propType.getSelectedItem().toString()));
			optType.addItemListener(listener);
			searchQueary = new JTextField(10);
			searchQueary.getDocument().addDocumentListener(listener);

			this.add(Box.createHorizontalStrut(5));
			this.add(butRemove);
			this.add(Box.createHorizontalStrut(5));
			this.add(propType);
			this.add(Box.createHorizontalStrut(5));
			this.add(optType);
			this.add(Box.createHorizontalStrut(5));
			this.add(searchQueary);
			this.add(Box.createHorizontalStrut(5));

		}

		/**
		 * The Listner for all of the components for this class
		 */
		class AdvListener implements ItemListener, DocumentListener
		{

			@Override
			public void itemStateChanged(ItemEvent arg0)
			{
				if (arg0.getSource() == propType)
				{
					optType.setModel(new DefaultComboBoxModel(guic.getAllowedSearchOptionsInStrings(propType.getSelectedItem().toString())));
				}
				checkSearch();
			}

			@Override
			public void changedUpdate(DocumentEvent e)
			{
				checkSearch();
			}

			@Override
			public void insertUpdate(DocumentEvent e)
			{
				checkSearch();

			}

			@Override
			public void removeUpdate(DocumentEvent e)
			{
				checkSearch();

			}
		}

		/**
		 * Creates the SearchOption class that can be generated from this class
		 * 
		 * @return retuns the search option returns null if it is not possible
		 *         to create
		 */
		public SearchOption getSearchOption()
		{
			ColumnField field = guic.getColumnField(propType.getSelectedItem().toString());
			if (field == null)
			{
				// field = new ColumnField("Hello", DataType.STRING, 7);
				return null;
			}
			try
			{
				switch (SearchOptionType.valueOf(optType.getSelectedItem().toString()))
				{
				case MIN:
				{
					return SearchOption.createSearchMin(field, Double.valueOf(searchQueary.getText()));
				}
				case MAX:
				{
					return SearchOption.createSearchMax(field, Double.valueOf(searchQueary.getText()));
				}
				case EQUALNUMBER:
				{
					return SearchOption.createSearchEqual(field, Double.valueOf(searchQueary.getText()));
				}
				case EQUALSTRING:
				{
					return SearchOption.createSearchEqual(field, searchQueary.getText());
				}
				case CONTAINS:
				{
					return SearchOption.createSearchContains(field, searchQueary.getText());
				}
				case STARTS_WITH:
				{
					return SearchOption.createSearchStartsWith(field, searchQueary.getText());
				}
				case ENDS_WITH:
				{
					return SearchOption.createSearchEndsWith(field, searchQueary.getText());
				}
				default:
				{
					return null;
				}
				}
			}
			catch (NumberFormatException e)
			{
				return null;
			}
		}
	}
}
